package com.my.main.common.encrypt;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.security.MessageDigest;
import java.util.Date;
import java.util.Random;

public class MD5 {
	
	private static final int MD5_LOOP = 18;
	private static final char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
	
	protected static Log logger = LogFactory.getLog(MD5.class);

	
	public static void main(String[] args) {
//		// 正常的一次性加密
//		System.out.println(MD5.encrypt("123456"));
		// 加盐的循环加密
		String str = MD5.encrypt("123456", "mybp", MD5_LOOP);
		System.out.println(str);
//		
//		System.out.println(MD5.encryptUserPassword("123456"));
//		System.out.println(MD5.isSamePassword("123456", "25d608758ee60aa6162f7ddf1df54b2e"));
	}
	
	
	/**
	 * 判断密码是否相同
	 * @param inputPassword	用户输入密码
	 * @param dbPassword	数据库中存储的密码
	 * @return				true:相同，false:不同
	 */
	public static boolean isSamePassword(String inputPassword, String dbPassword) {
		
		if(inputPassword==null || dbPassword==null || dbPassword.length()!=32) {
			return false;
		}
		
		String salt = dbPassword.substring(0, 4);
		inputPassword = encrypt(inputPassword, salt, MD5_LOOP);
		return dbPassword.equals(salt+inputPassword.substring(0, 28));
		
	}
	/**
	 * 给用户密码加密
	 * @param inputPassword	明文密码
	 * @return				密文
	 */
	public static String encryptUserPassword(String inputPassword) {
		String salt = getRandomSalt(4);
		inputPassword = encrypt(inputPassword, salt, MD5_LOOP);
		return salt+inputPassword.substring(0, 28);
	}
	

	/**
	 * 加密
	 * @param str		明文
	 * @param salt		盐，不为空
	 * @param loop		循环次数，大于1
	 * @return			密文
	 */
	private static String encrypt(String str, String salt, int loop) {
		String encryptStr = encrypt(str);
		try {
			for(int i=0; i<loop; i++) {
				encryptStr = encrypt(salt+encryptStr).substring(0, 32);
			}
		} 
		catch (Exception e) {
			logger.error(e);
		}
		return encryptStr;
	}
	
	/**
	 * 加密
	 * @param str		明文
	 * @return			密文
	 */
	public static String encrypt(String str) {
		MessageDigest md = null;
		try {
			// 获得MD5摘要算法的 MessageDigest 对象
			md = MessageDigest.getInstance("MD5");
			// 使用指定的字节更新摘要
			md.update(str.getBytes("utf-8"));
			// 转换加密
			byte[] bytes = md.digest();
			int l = bytes.length;
			char[] out = new char[l << 1];
			int i = 0;
			for (int j = 0; i < l; i++) {
				out[(j++)] = DIGITS[((0xF0 & bytes[i]) >>> 4)];
				out[(j++)] = DIGITS[(0xF & bytes[i])];
			}
			str = new String(out);
		}
		catch (Exception e) {
			logger.error(e);
		}
		return str;
	}
	
	
	/**
	 * 随机生成盐
	 * 为了达到不易被识别的目的，将盐的字符限制为0-9a-f的范围
	 * （个人觉得，既然是盐就没有这个必要了吧？）
	 * 
	 * @param type		生成字符串的类型，0:字母,1:数字,2字母+数字
	 * @param length	生成字符串的长度
	 * @return
	 */
	private static String getRandomSalt(int length) {
		String words = "0123456789abcdef";

		Random random = new Random(new Date().getTime());
		StringBuffer stringBuffer = new StringBuffer();
		for (int i=0; i<length; i++) {
			int index = random.nextInt(words.length());
			stringBuffer.append(words.charAt(index));
		}
		return stringBuffer.toString();
	}

}
